#include <stdarg.h>
#include <stdint.h>
#include "common_test.h"
#include "log.h"
#include "mem_test.h"
#include "perh_reg_lpddr5_ss.h"

typedef uint32_t u32;
extern uint32_t _end;

static int32_t _mem8_test(const uint8_t data, uint8_t * start_addr, uint8_t * end_addr);
static int32_t mem8_test(uint8_t * start_addr, uint8_t * end_addr);

static int32_t _mem16_test(const uint16_t data, uint16_t * start_addr, uint16_t * end_addr);
static int32_t mem16_test(uint16_t * start_addr, uint16_t * end_addr);

static int32_t _mem32_test(const uint32_t data, uint32_t * start_addr, uint32_t * end_addr);
static int32_t mem32_test(uint32_t * start_addr, uint32_t * end_addr);

static int32_t _mem8_test(const uint8_t data, uint8_t * start_addr, uint8_t * end_addr)
{
    uint32_t ret = 0;
    uint8_t *const p_start = (uint8_t *)(start_addr);
    uint8_t *const p_end = (uint8_t *)(end_addr);
    volatile uint8_t *p_data = p_start;
    uint32_t cnt= 0;

    // LOGD("Write data[0x%02x] to mem to test start\r\n", data);

    for (p_data = p_start; p_data < p_end; p_data ++) {
        *p_data = data;
    }

    for (p_data = p_start; p_data < p_end; p_data ++) {
        cnt++;  
        if (*p_data != data) {
            LOGE("Addr[%08p], Expect 0x%02x, Get 0x%02x\r\n",p_data, data,* p_data);
            ret = -1;
            break;
        }
        LOGD("Addr[%08p], Expect 0x%02x, Get 0x%02x\r\n",p_data, data,* p_data);
    }
    // LOGD("Write data[0x%02x] to mem to test end, cmpare cnt[0x%08x]\r\n", data, cnt);
    return ret;
}

static int32_t mem8_test(uint8_t * start_addr, uint8_t * end_addr)
{
    int32_t ret = 0;
    ret = _mem8_test(0x5A,start_addr,end_addr);
    TEST_ASSRT(0 == ret);
    ret = _mem8_test(0xFF,start_addr,end_addr);
    TEST_ASSRT(0 == ret);
    ret = _mem8_test(0x99,start_addr,end_addr);
    TEST_ASSRT(0 == ret);
    return ret;
}

static int32_t _mem16_test(const uint16_t data, uint16_t * start_addr, uint16_t * end_addr)
{
    uint32_t ret = 0;
    uint16_t *const p_start = (uint16_t *)(start_addr);
    uint16_t *const p_end = (uint16_t *)(end_addr);
    volatile uint16_t *p_data = p_start;
    uint32_t cnt= 0;

    // LOGD("Write data[0x%04x] to mem to test start\r\n", data);

    for (p_data = p_start; p_data < p_end; p_data ++) {
        *p_data = data;
    }

    for (p_data = p_start; p_data < p_end; p_data ++) {
        cnt++;  
        if (*p_data != data) {
            LOGE("Addr[%08p], Expect 0x%04x, Get 0x%04x\r\n",p_data, data,* p_data);
            ret = -1;
            break;
        }
        LOGD("Addr[%08p], Expect 0x%04x, Get 0x%04x\r\n",p_data, data,* p_data);
    }
    // LOGD("Write data[0x%04x] to mem to test end, cmpare cnt[0x%08x]\r\n", data, cnt);
    return ret;
}

static int32_t mem16_test(uint16_t * start_addr, uint16_t * end_addr)
{
    int32_t ret = 0;
    ret = _mem16_test(0x5A5A,start_addr,end_addr);
    TEST_ASSRT(0 == ret);
    ret = _mem16_test(0xFF00,start_addr,end_addr);
    TEST_ASSRT(0 == ret);
    ret = _mem16_test(0x9955,start_addr,end_addr);
    TEST_ASSRT(0 == ret);
    return ret;
}

static int32_t _mem32_test(const uint32_t data, uint32_t * start_addr, uint32_t * end_addr)
{
    uint32_t ret = 0;
    uint32_t *const p_start = (uint32_t *)(start_addr);
    uint32_t *const p_end = (uint32_t *)(end_addr);
    volatile uint32_t *p_data = p_start;
    uint32_t cnt= 0;

    LOGD("Write data[0x%08x] to mem to test start\r\n", data);

    for (p_data = p_start; p_data < p_end; p_data ++) {
        *p_data = data;
    }

    for (p_data = p_start; p_data < p_end; p_data ++) {
        cnt++;  
        if (*p_data != data) {
            LOGE("Addr[%08p], Expect 0x%08x, Get 0x%08x\r\n",p_data, data,* p_data);
            ret = -1;
            break;
        }
        // LOGD("Addr[%08p], Expect 0x%08x, Get 0x%08x\r\n",p_data, data,* p_data);
    }
    LOGD("Write data[0x%08x] to mem to test end, cmpare cnt[0x%08x]\r\n", data, cnt);
    return ret;
}

// static int32_t _mem32_test(const uint32_t data, uint32_t * start_addr, uint32_t * end_addr)
// {
//     uint32_t ret = 0;
//     uint32_t *const p_start = (uint32_t *)(start_addr);
//     uint32_t *const p_end = (uint32_t *)(end_addr);
//     volatile uint32_t *p_data = p_start;
//     uint32_t cnt= 0;
//     // uint32_t mask = 0x00FF00FF;
//     uint32_t mask = 0xFFFFFFFF;
//     uint32_t rdcycle = 0;
//     uint32_t random_addr = 0;
//     uint32_t random_data = 0;
//     uint32_t rdata = 0;
//     uint32_t read_cnt = 16;
//     uint32_t read_buffer[1024] = {0};

//     // LOGD("Write data[0x%08x] to mem to test start\r\n", data);
//     random_addr = rand(time());
//     random_data = rand(time());

//     *p_data = random_data;

//     for(int i = 0; i < read_cnt; i ++)
//     {
//         read_buffer[i] = *p_data;
//     }
//     for(int i = 0; i < read_cnt; i ++)
//     {
//         LOGD("Read_cnt[%d] Addr[%08p], Expect 0x%08x, Get 0x%08x\r\n", i, p_data, (random_data & mask),((read_buffer[i]) & mask));
//         if (((read_buffer[i]) & mask) != (random_data & mask) ) {
//             LOGE("Addr[%08p], Expect 0x%08x, Get 0x%08x\r\n",p_data, (random_data & mask),((rdata) & mask));
//             ret = -1;
//             break;
//         }
//     }

//     for (p_data = p_start; p_data < p_end; p_data ++) {
//         random_data = rand(time());
//         *p_data = random_data;
//  //       break;
//         // DELAY(0xfffffff);

//         rdata = *p_data;
//         LOGD("Addr[%08p], Expect 0x%08x, Get 0x%08x\r\n",p_data, (random_data & mask),((rdata) & mask));
//         rdata = *p_data;
//         if (((rdata) & mask) != (random_data & mask) ) {
//             LOGE("Addr[%08p], Expect 0x%08x, Get 0x%08x\r\n",p_data, (random_data & mask),((rdata) & mask));
//             ret = -1;
//             break;
//         }
//     }
//     return ret;
// }

static int32_t _mem32_random_test(const uint32_t data, uint32_t * start_addr, uint32_t * end_addr)
{
    uint32_t ret = 0;
    uint32_t *const p_start = (uint32_t *)(start_addr);
    uint32_t *const p_end = (uint32_t *)(end_addr);
    volatile uint32_t *p_data = p_start;
    uint32_t cnt= 0;
    // uint32_t mask = 0x00FF00FF;
    uint32_t mask = 0xFFFFFFFF;
    uint32_t rdcycle = 0;
    volatile uint32_t *random_addr;
    uint32_t random_data = 0;
    uint32_t rdata = 0;
    uint32_t read_cnt = 16;
    uint32_t read_buffer[1024] = {0};
    uint32_t loop_cnt = 32;

    #if (EN_PRESSURE_TEST)
        // while(1)
        {
            rdcycle     = time();
            random_data = rand(rdcycle);
            random_addr = p_start + (random_data / sizeof(uint32_t)); // random all space 4GB
            // random_addr = p_start + (random_data / sizeof(uint32_t) / (256 * 1024 * 1024)); // random all space 256MB fixme
            // random_addr = p_start + (random_data / (64 * 1024) / sizeof(uint32_t)); // random 64K 
            // random_addr = p_start;
            rdcycle     = time();
            random_data = rand(rdcycle);
            // write data to addr
            *random_addr = random_data;
            // read data from addr
            rdata = *random_addr;
            LOGD("Addr[%08p], Expect 0x%08x, Get 0x%08x\r\n", random_addr, (random_data & mask), ((rdata) & mask));
            if (((rdata) & mask) != (random_data & mask) ) {
                LOGE("Addr[%08p], Expect 0x%08x, Get 0x%08x\r\n", random_addr, (random_data & mask), ((rdata) & mask));
                ret = -1;
                // break;
            }
        }
    #else
        while(loop_cnt --) 
        {
            rdcycle = time();
            // random_addr = p_start + (rand(rdcycle) / sizeof(uint32_t)); // random all space 4GB
            random_addr = p_start + (rand(rdcycle) / (64 * 1024) / sizeof(uint32_t)); // random 64K 
            rdcycle = time();
            random_data = rand(rdcycle);
            // write data to addr
            *random_addr = random_data;
            // read data from addr
            rdata = *random_addr;
            LOGD("Addr[%08p], Expect 0x%08x, Get 0x%08x\r\n", random_addr, (random_data & mask), ((rdata) & mask));
            if (((rdata) & mask) != (random_data & mask) ) {
                LOGE("Addr[%08p], Expect 0x%08x, Get 0x%08x\r\n", random_addr, (random_data & mask), ((rdata) & mask));
                ret = -1;
                // break;
            }
        }
        LOGD("memory test done!\r\n");
    #endif

    return ret;
}

static int32_t mem32_test(uint32_t * start_addr, uint32_t * end_addr)
{
    int32_t ret = 0;
    // ret = _mem32_test(0x12345678,start_addr,end_addr);
    ret = _mem32_random_test(0x12345678,start_addr,end_addr);
    TEST_ASSRT(0 == ret);
    // ret = _mem32_test(0x5A5A5A5A,start_addr,end_addr);
    // TEST_ASSRT(0 == ret);
    // ret = _mem32_test(0xFFFFFFFF,start_addr,end_addr);
    // TEST_ASSRT(0 == ret);
    // ret = _mem32_test(0x00000000,start_addr,end_addr);
    // TEST_ASSRT(0 == ret);
    return ret;
}

int32_t mem_test(void)
{
    LOGI("Start Memory test, SRAM Range[%08p~0x%8x]\r\n", TEST_START_MEM_ADDR, TEST_END_MEM_ADDR);
#if (EN_PRESSURE_TEST)
    uint32_t test_cnt = 0;
    int32_t ret = 0;

    while (1) {
        ret = mem8_test(TEST_START_MEM_ADDR,TEST_END_MEM_ADDR);
        ret = mem16_test(TEST_START_MEM_ADDR,TEST_END_MEM_ADDR);
        ret = mem32_test(TEST_START_MEM_ADDR,TEST_END_MEM_ADDR);
        test_cnt++;
        if(0 == (test_cnt % 50)) {
            LOGI("test cnt = %d\r\n", test_cnt);
        }
    }
    return ret;
#else
    int32_t ret = 0;
    ret = mem8_test(TEST_START_MEM_ADDR,TEST_END_MEM_ADDR);
    ret = mem16_test(TEST_START_MEM_ADDR,TEST_END_MEM_ADDR);
    ret=  mem32_test(TEST_START_MEM_ADDR,TEST_END_MEM_ADDR);
    return ret;
#endif
}

int32_t ddr0_test(void)
{
    LOGI("Start DDR0 test, DDR0 Range[%08p~0x%8lx]\r\n", TEST_START_DDR0_ADDR, TEST_END_DDR0_ADDR);
#if (EN_PRESSURE_TEST)
    uint64_t test_cnt = 0;
    int32_t ret = 0;

    while (1) {
        // ret = mem8_test(TEST_START_DDR0_ADDR,TEST_END_DDR0_ADDR);
        // ret = mem16_test(TEST_START_DDR0_ADDR,TEST_END_DDR0_ADDR);
        ret = mem32_test(TEST_START_DDR0_ADDR,TEST_END_DDR0_ADDR);
        test_cnt++;
        if(0 == (test_cnt % 500)) {
            LOGI("test cnt = %d\r\n", test_cnt);
        }
    }
    return ret;
#else
    int32_t ret = 0;
    // ret = mem8_test(TEST_START_DDR0_ADDR,TEST_END_DDR0_ADDR);
    // ret = mem16_test(TEST_START_DDR0_ADDR,TEST_END_DDR0_ADDR);
    ret=  mem32_test(TEST_START_DDR0_ADDR,TEST_END_DDR0_ADDR);
    return ret;
#endif

}

int32_t ddr1_test(void)
{
    LOGI("Start DDR1 test, DDR1 Range[%08p~0x%8lx]\r\n", TEST_START_DDR1_ADDR, TEST_END_DDR1_ADDR);
#if (EN_PRESSURE_TEST)
    uint64_t test_cnt = 0;
    int32_t ret = 0;

    while (1) {
        // ret = mem8_test(TEST_START_DDR1_ADDR,TEST_END_DDR1_ADDR);
        // ret = mem16_test(TEST_START_DDR1_ADDR,TEST_END_DDR1_ADDR);
        ret = mem32_test(TEST_START_DDR1_ADDR,TEST_END_DDR1_ADDR);
        test_cnt++;
        if(0 == (test_cnt % 500)) {
            LOGI("test cnt = %d\r\n", test_cnt);
        }
    }
    return ret;
#else
    int32_t ret = 0;
    // ret = mem8_test(TEST_START_DDR1_ADDR,TEST_END_DDR1_ADDR);
    // ret = mem16_test(TEST_START_DDR1_ADDR,TEST_END_DDR1_ADDR);
    ret=  mem32_test(TEST_START_DDR1_ADDR,TEST_END_DDR1_ADDR);
    return ret;
#endif

}

#ifdef EN_MEM_TEST_OPENSOURCE
/* Function definitions. */

int test_stuck_address(volatile unsigned long *bufa, u32 count);
int test_random_value(volatile unsigned long *bufa,
		      volatile unsigned long *bufb, u32 count);
int test_xor_comparison(volatile unsigned long *bufa,
			volatile unsigned long *bufb, u32 count);
int test_sub_comparison(volatile unsigned long *bufa,
			volatile unsigned long *bufb, u32 count);
int test_mul_comparison(volatile unsigned long *bufa,
			volatile unsigned long *bufb, u32 count);
int test_div_comparison(volatile unsigned long *bufa,
			volatile unsigned long *bufb, u32 count);
int test_or_comparison(volatile unsigned long *bufa,
		       volatile unsigned long *bufb, u32 count);
int test_and_comparison(volatile unsigned long *bufa,
			volatile unsigned long *bufb, u32 count);
int test_seqinc_comparison(volatile unsigned long *bufa,
			   volatile unsigned long *bufb, u32 count);
int test_solidbits_comparison(volatile unsigned long *bufa,
			      volatile unsigned long *bufb, u32 count);
int test_checkerboard_comparison(volatile unsigned long *bufa,
				 volatile unsigned long *bufb, u32 count);
int test_blockseq_comparison(volatile unsigned long *bufa,
			     volatile unsigned long *bufb, u32 count);
int test_walkbits0_comparison(volatile unsigned long *bufa,
			      volatile unsigned long *bufb, u32 count);
int test_walkbits1_comparison(volatile unsigned long *bufa,
			      volatile unsigned long *bufb, u32 count);
int test_bitspread_comparison(volatile unsigned long *bufa,
			      volatile unsigned long *bufb, u32 count);
int test_bitflip_comparison(volatile unsigned long *bufa,
			    volatile unsigned long *bufb, u32 count);
int test_8bit_wide_random(volatile unsigned long *bufa,
			  volatile unsigned long *bufb, u32 count);
int test_16bit_wide_random(volatile unsigned long *bufa,
			   volatile unsigned long *bufb, u32 count);

#define UL_LEN 64
#define UL_ONEBITS 0xffffffffffffffffUL
#define CHECKERBOARD1 0x5555555555555555
#define CHECKERBOARD2 0xaaaaaaaaaaaaaaaa
#define UL_BYTE(x)                                                            \
	(((unsigned long)x | (unsigned long)x << 8 | (unsigned long)x << 16 | \
	  (unsigned long)x << 24 | (unsigned long)x << 32 |                   \
	  (unsigned long)x << 40 | (unsigned long)x << 48 |                   \
	  (unsigned long)x << 56))
#define ONE 0x00000001L

union {
	unsigned char bytes[UL_LEN / 8];
	unsigned long val;
} mword8;

union {
	unsigned short u16s[UL_LEN / 16];
	unsigned long val;
} mword16;

struct test {
	char *name;
	int (*fp)(volatile unsigned long *bufa, volatile unsigned long *bufb,
		  u32 count);
};

struct test tests[] = { { "Random Value", test_random_value },
			{ "Compare XOR", test_xor_comparison },
			{ "Compare SUB", test_sub_comparison },
			{ "Compare MUL", test_mul_comparison },
			{ "Compare DIV", test_div_comparison },
			{ "Compare OR", test_or_comparison },
			{ "Compare AND", test_and_comparison },
			{ "Sequential Increment", test_seqinc_comparison },
			{ "Solid Bits", test_solidbits_comparison },
			{ "Block Sequential", test_blockseq_comparison },
			{ "Checkerboard", test_checkerboard_comparison },
			{ "Bit Spread", test_bitspread_comparison },
			{ "Bit Flip", test_bitflip_comparison },
			{ "Walking Ones", test_walkbits1_comparison },
			{ "Walking Zeroes", test_walkbits0_comparison },
			{ "8-bit Writes", test_8bit_wide_random },
			{ "16-bit Writes", test_16bit_wide_random },
			{ NULL, NULL } };

int compare_regions(volatile unsigned long *bufa, volatile unsigned long *bufb,
		    u32 count)
{
	int r = 0;
	u32 i;

	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;

	for (i = 0; i < count; i++, p1++, p2++) {
		if (*p1 != *p2) {
			printf("fail\r\n");
			r = -1;
		}
	}
	return r;
}

int test_mul_comparison(volatile unsigned long *bufa,
			volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	u32 i;
	long rand_num, q;

	rand_num = rand(time());
	q = rand_num;

	for (i = 0; i < count; i++) {
		*p1++ *= q;
		*p2++ *= q;
	}
	return compare_regions(bufa, bufb, count);
}

int test_div_comparison(volatile unsigned long *bufa,
			volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	u32 i;
	long rand_num, q;

	rand_num = rand(time());
	q = rand_num;

	for (i = 0; i < count; i++) {
		if (!q)
			q++;
		*p1++ /= q;
		*p2++ /= q;
	}
	return compare_regions(bufa, bufb, count);
}

int test_or_comparison(volatile unsigned long *bufa,
		       volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	u32 i;
	long rand_num, q;

	rand_num = rand(time());
	q = rand_num;

	for (i = 0; i < count; i++) {
		*p1++ |= q;
		*p2++ |= q;
	}
	return compare_regions(bufa, bufb, count);
}

int test_and_comparison(volatile unsigned long *bufa,
			volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	u32 i;
	long rand_num, q;

	rand_num = rand(time());
	q = rand_num;

	for (i = 0; i < count; i++) {
		*p1++ &= q;
		*p2++ &= q;
	}
	return compare_regions(bufa, bufb, count);
}

int test_seqinc_comparison(volatile unsigned long *bufa,
			   volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	u32 i;
	long rand_num, q;

	rand_num = rand(time());
	q = rand_num;

	for (i = 0; i < count; i++)
		*p1++ = *p2++ = (i + q);
	return compare_regions(bufa, bufb, count);
}

int test_solidbits_comparison(volatile unsigned long *bufa,
			      volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	unsigned int j;
	unsigned long q;
	u32 i;

	for (j = 0; j < 64; j++) {
		q = (j % 2) == 0 ? UL_ONEBITS : 0;
		p1 = (volatile unsigned long *)bufa;
		p2 = (volatile unsigned long *)bufb;
		for (i = 0; i < count; i++) {
			*p1++ = *p2++ = (i % 2) == 0 ? q : ~q;
		}
		if (compare_regions(bufa, bufb, count))
			return -1;
	}
	return 0;
}

int test_checkerboard_comparison(volatile unsigned long *bufa,
				 volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	unsigned int j;
	unsigned long q;
	u32 i;

	for (j = 0; j < 64; j++) {
		q = (j % 2) == 0 ? CHECKERBOARD1 : CHECKERBOARD2;
		p1 = (volatile unsigned long *)bufa;
		p2 = (volatile unsigned long *)bufb;
		for (i = 0; i < count; i++) {
			*p1++ = *p2++ = (i % 2) == 0 ? q : ~q;
		}
		if (compare_regions(bufa, bufb, count))
			return -1;
	}
	return 0;
}

int test_blockseq_comparison(volatile unsigned long *bufa,
			     volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	unsigned int j;
	u32 i;

	for (j = 0; j < 256; j++) {
		p1 = (volatile unsigned long *)bufa;
		p2 = (volatile unsigned long *)bufb;
		for (i = 0; i < count; i++) {
			*p1++ = *p2++ = (unsigned long)UL_BYTE(j);
		}
		if (compare_regions(bufa, bufb, count))
			return -1;
	}
	return 0;
}

int test_walkbits0_comparison(volatile unsigned long *bufa,
			      volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	unsigned int j;
	u32 i;

	for (j = 0; j < UL_LEN * 2; j++) {
		p1 = (volatile unsigned long *)bufa;
		p2 = (volatile unsigned long *)bufb;
		for (i = 0; i < count; i++) {
			if (j < UL_LEN) { /* Walk it up. */
				*p1++ = *p2++ = ONE << j;
			} else { /* Walk it back down. */
				*p1++ = *p2++ = ONE << (UL_LEN * 2 - j - 1);
			}
		}
		if (compare_regions(bufa, bufb, count))
			return -1;
	}
	return 0;
}

int test_walkbits1_comparison(volatile unsigned long *bufa,
			      volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	unsigned int j;
	u32 i;

	for (j = 0; j < UL_LEN * 2; j++) {
		p1 = (volatile unsigned long *)bufa;
		p2 = (volatile unsigned long *)bufb;
		for (i = 0; i < count; i++) {
			if (j < UL_LEN) { /* Walk it up. */
				*p1++ = *p2++ = UL_ONEBITS ^ (ONE << j);
			} else { /* Walk it back down. */
				*p1++ = *p2++ = UL_ONEBITS ^
						(ONE << (UL_LEN * 2 - j - 1));
			}
		}
		if (compare_regions(bufa, bufb, count))
			return -1;
	}
	return 0;
}

int test_bitspread_comparison(volatile unsigned long *bufa,
			      volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	unsigned int j;
	u32 i;

	for (j = 0; j < UL_LEN * 2; j++) {
		p1 = (volatile unsigned long *)bufa;
		p2 = (volatile unsigned long *)bufb;
		for (i = 0; i < count; i++) {
			if (j < UL_LEN) { /* Walk it up. */
				*p1++ = *p2++ =
					(i % 2 == 0) ?
						(ONE << j) | (ONE << (j + 2)) :
						UL_ONEBITS ^ ((ONE << j) |
							      (ONE << (j + 2)));
			} else /* Walk it back down. */
				*p1++ = *p2++ =
					(i % 2 == 0) ?
						(ONE << (UL_LEN * 2 - 1 - j)) |
							(ONE << (UL_LEN * 2 +
								 1 - j)) :
						UL_ONEBITS ^
							(ONE << (UL_LEN * 2 -
								 1 - j) |
							 (ONE << (UL_LEN * 2 +
								  1 - j)));
		}
		if (compare_regions(bufa, bufb, count))
			return -1;
	}
	return 0;
}

int test_bitflip_comparison(volatile unsigned long *bufa,
			    volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	unsigned int j, k;
	unsigned long q;
	u32 i;

	for (k = 0; k < UL_LEN; k++) {
		q = ONE << k;
		for (j = 0; j < 8; j++) {
			q = ~q;
			p1 = (volatile unsigned long *)bufa;
			p2 = (volatile unsigned long *)bufb;
			for (i = 0; i < count; i++) {
				*p1++ = *p2++ = (i % 2) == 0 ? q : ~q;
			}
			if (compare_regions(bufa, bufb, count))
				return -1;
		}
	}
	return 0;
}

int test_8bit_wide_random(volatile unsigned long *bufa,
			  volatile unsigned long *bufb, u32 count)
{
	unsigned char volatile *p1, *t;
	volatile unsigned long *p2;
	int attempt;
	unsigned int b;
	u32 i;
	long rand_num;

	for (attempt = 0; attempt < 2; attempt++) {
		if (attempt & 1) {
			p1 = (unsigned char volatile *)bufa;
			p2 = bufb;
		} else {
			p1 = (unsigned char volatile *)bufb;
			p2 = bufa;
		}
		for (i = 0; i < count; i++) {
			t = mword8.bytes;
			rand_num = rand(time());
			*p2++ = mword8.val = rand_num;

			for (b = 0; b < UL_LEN / 8; b++)
				*p1++ = *t++;
		}
		if (compare_regions(bufa, bufb, count))
			return -1;
	}
	return 0;
}

int test_16bit_wide_random(volatile unsigned long *bufa,
			   volatile unsigned long *bufb, u32 count)
{
	unsigned short volatile *p1, *t;
	volatile unsigned long *p2;
	int attempt;
	unsigned int b;
	u32 i;
	long rand_num;

	for (attempt = 0; attempt < 2; attempt++) {
		if (attempt & 1) {
			p1 = (unsigned short volatile *)bufa;
			p2 = bufb;
		} else {
			p1 = (unsigned short volatile *)bufb;
			p2 = bufa;
		}
		for (i = 0; i < count; i++) {
			t = mword16.u16s;
			rand_num = rand(time());
			*p2++ = mword16.val = rand_num;

			for (b = 0; b < UL_LEN / 16; b++)
				*p1++ = *t++;
		}
		if (compare_regions(bufa, bufb, count))
			return -1;
	}
	return 0;
}

int test_sub_comparison(volatile unsigned long *bufa,
			volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	u32 i;
	long rand_num, q;

	rand_num = rand(time());
	q = rand_num;

	for (i = 0; i < count; i++) {
		*p1++ -= q;
		*p2++ -= q;
	}
	return compare_regions(bufa, bufb, count);
}

int test_xor_comparison(volatile unsigned long *bufa,
			volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	u32 i;
	long rand_num, q;

	rand_num = rand(time());
	q = rand_num;

	for (i = 0; i < count; i++) {
		*p1++ ^= q;
		*p2++ ^= q;
	}
	return compare_regions(bufa, bufb, count);
}

int test_random_value(volatile unsigned long *bufa,
		      volatile unsigned long *bufb, u32 count)
{
	volatile unsigned long *p1 = bufa;
	volatile unsigned long *p2 = bufb;
	u32 i;
	long rand_num;

	for (i = 0; i < count; i++) {
		rand_num = rand(time());
		*p1++ = *p2++ = rand_num;
	}
	return compare_regions(bufa, bufb, count);
}

int test_stuck_address(volatile unsigned long *bufa, u32 count)
{
	volatile unsigned long *p1 = bufa;
	unsigned int j;
	u32 i;

	for (j = 0; j < 16; j++) {
		p1 = bufa;
		for (i = 0; i < count; i++) {
			*p1 = ((j + i) % 2) == 0 ? (unsigned long)p1 : ~((unsigned long)p1);
			*p1++;
		}
		p1 = bufa;
		for (i = 0; i < count; i++, p1++) {
			if (*p1 !=
			    (((j + i) % 2) == 0 ? (unsigned long)p1 : ~((unsigned long)p1))) {
				printf("Skipping to next test...\r\n");
				return -1;
			}
		}
	}
	return 0;
}

int mem0_test_opensource(unsigned long off, unsigned long size)
{
	void *ddr_base;
	volatile unsigned long *bufa, *bufb;
	u32 count, i, halflen;

	ddr_base = TEST_START_DDR0_ADDR;

	halflen = size / 2;
	count = size / sizeof(long);
	bufa = (volatile unsigned long *)(ddr_base + off);

	printf(":\r\n");
	printf("  %-20s: ", "Stuck Address");
	if (!test_stuck_address(bufa, count))
		printf("ok\r\n");
	else
		printf("fail\r\n");

	count = halflen / sizeof(long);
	bufb = bufa + count;
	for (i = 0;; i++) {
		if (!tests[i].name)
			break;
		/* If using a custom testmask, only run this test if the
		 *  bit corresponding to this test was set by the user.
		 */
		printf("  %-20s: ", tests[i].name);
		if (!tests[i].fp(bufa, bufb, count))
			printf("ok\r\n");
		else
			printf("fail\r\n");
	}
	printf("\r\n");
	printf("Done.\r\n");
	return 0;
}

int mem1_test_opensource(unsigned long off, unsigned long size)
{
	void *ddr_base;
	volatile unsigned long *bufa, *bufb;
	u32 count, i, halflen;

	ddr_base = TEST_START_DDR1_ADDR;

	halflen = size / 2;
	count = size / sizeof(long);
	bufa = (volatile unsigned long *)(ddr_base + off);

	printf(":\r\n");
	printf("  %-20s: ", "Stuck Address");
	if (!test_stuck_address(bufa, count))
		printf("ok\r\n");
	else
		printf("fail\r\n");

	count = halflen / sizeof(long);
	bufb = bufa + count;
	for (i = 0;; i++) {
		if (!tests[i].name)
			break;
		/* If using a custom testmask, only run this test if the
		 *  bit corresponding to this test was set by the user.
		 */
		printf("  %-20s: ", tests[i].name);
		if (!tests[i].fp(bufa, bufb, count))
			printf("ok\r\n");
		else
			printf("fail\r\n");
	}
	printf("\r\n");
	printf("Done.\r\n");
	return 0;
}
#endif //#ifdef MEM_TEST

